#pragma once

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cstring>
#include <unistd.h>

class UdpClient{
  private:
    int sockfd;
    std::string server_ip;//作为客户端需要直到连接的服务器IP地址
    int server_port; //需要直到链接到服务器的哪个端口
  public:
    UdpClient(std::string _ip,int _port)
      :server_ip(_ip),server_port(_port)
    {}

    bool InitUdpClient()
    {
        sockfd = socket(AF_INET,SOCK_DGRAM,0);
        if(sockfd < 0){
          std::cerr << "socket error!" << std::endl;
          return false;
        }
        //客户端不需要port吗？客户端不需要绑定吗？
        //一定需要port，因为是网络编程，也是套接字编程，所以一定需要端口地址。
        //客户端不需要绑定（不代表不能），因为客户端方位服务器，端口只要是唯一的即可，不需要和特定的客户端进程强相关。服务器之所以需要绑定端口，是因位服务器是给别人服务的，而端口就是提供服务进程的进程编号，所以客户一定需要直到你的IP和端口。端口一定要是一个众所周知的端口，而且bind之后，不能轻易改变
        
        return true;
    }

    void Start()
    {
      struct sockaddr_in peer;
      memset(&peer,0,sizeof(peer));
      
      peer.sin_family = AF_INET;
      peer.sin_port = htons(server_port);//主机转网络
      peer.sin_addr.s_addr = inet_addr(server_ip.c_str());

      std::string msg;
      for(; ; ){
        std::cout << "Please Enter# ";
        std::cin >> msg;
        sendto(sockfd,msg.c_str(),msg.size(),0,(struct sockaddr*)&peer,sizeof(peer));

        char buffer[128];
        struct sockaddr_in temp;
        socklen_t len = sizeof(temp);
        ssize_t size = recvfrom(sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);
        if(size > 0)
        {
          buffer[size] = 0;
          std::cout << buffer << std::endl;
        }
      }
    }

    ~UdpClient()
    {
      if(sockfd >= 0)
        close(sockfd);
    }
};
